package Phase;

import Entities.Advantages.IAdvantage;
import Entities.Ball;
import Entities.Bar;
import Entities.Brick;
import Entities.Drawable;
import Entities.Scene;
import StateInformation.GameState;
import Visitor.BallCollisionVisitor;
import Visitor.BarCollisionVisitor;
import Visitor.IVisitor;
import Visitor.MoveVisitor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.Timer;

public class AnimationController extends Thread {
    
    private Scene scene;
    private GameState gameState;
    private ArrayList<Ball> ballList;
    private Bar bar;
    private boolean rigthPressed = false;
    private boolean leftPressed = false;
    private boolean spacePressed = false;
    private int maxWidth;
    private PhaseController phaseController;
    private boolean stop;
    private Timer timer;
    private boolean gameStarted;
    
    public AnimationController(Scene scene, final GameState gameState, Bar bar, Ball ball, int maxWidth, PhaseController phaseController) {
        this.scene = scene;
        this.gameState = gameState;
        this.phaseController = phaseController;
        this.bar = bar;
        this.maxWidth = maxWidth;
        
        ballList = new ArrayList<>();
        ballList.add(ball);
        stop = false;
        
        timer = new Timer(1000, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                gameState.increaseTime();
            }
        });
        
        gameStarted = false;
    }
    
    @Override
    public void run() {
        while (!stop) {
            if (spacePressed) {
                gameStarted = true;
                timer.start();
            }
            if (!gameStarted) {
                timer.stop();
            }
            try {
                Drawable drawable = null;
                IVisitor barCollisionVisitor = new BarCollisionVisitor(bar);
                drawable = scene.accept(barCollisionVisitor);
                if (drawable != null) {
                    IAdvantage a = (IAdvantage) drawable;
                    // Aplicador.aplicar (a);
                    scene.remove(drawable);
                }
                synchronized (ballList) {
                    for (Ball b : ballList) {
                        IVisitor ballCollisionVisitor = new BallCollisionVisitor(b);
                        drawable = scene.accept(ballCollisionVisitor);
                        if (drawable != null && Brick.class.getName().equals(drawable.getClass().getName())) {
                            Brick brick = (Brick) drawable;
                            if (brick.getResistance() == 0) {
                                if (brick.getAdvantage() != null) {
                                    scene.addChild(brick.getAdvantage());
                                    brick.getAdvantage().setDy(1);
                                }
                                gameState.setScore(gameState.getScore() + brick.getScore());
                                
                                scene.remove(drawable);
                            } else {
                                brick.setResistance(brick.getResistance() - 1);
                            }
                        }
                    }
                    IVisitor moveVisitor = new MoveVisitor(leftPressed, rigthPressed, spacePressed, maxWidth);
                    scene.accept(moveVisitor);
                    deadBall();
                    phaseFinished();
                }
                Thread.sleep(5);
            } catch (InterruptedException ex) {
                Logger.getLogger(AnimationController.class.getName()).log(Level.SEVERE, null, ex);
            } catch (ClassCastException e) {
                System.out.println("Error de casting");
            }
        }
        timer.stop();
    }
    
    public void setRigthPressed(boolean rigthPressed) {
        this.rigthPressed = rigthPressed;
    }
    
    public void setLeftPressed(boolean leftPressed) {
        this.leftPressed = leftPressed;
    }
    
    public void setSpacePressed(boolean spacePressed) {
        this.spacePressed = spacePressed;
    }
    
    private void deadBall() {
        int i = -1;
        synchronized (ballList) {
            for (Ball ball : ballList) {
                if (ball.getY() > bar.getY()) {
                    i = ballList.indexOf(ball);
                }
            }
            synchronized (scene) {
                if (i != -1) {
                    scene.remove(ballList.get(i));
                    ballList.remove(i);
                    gameState.setNumberOfLifes(gameState.getNumberOfLifes() - 1);
                    
                }
            }
        }
    }
    
    private void phaseFinished() {
        ArrayList<Brick> brickList = new ArrayList<>();
        synchronized (scene) {
            for (int i = 0; i < scene.getNumElems(); i++) {
                try {
                    Brick brick = (Brick) scene.getChild(i);
                    brickList.add(brick);
                } catch (ClassCastException e) {
                }
            }
            if (ballList.isEmpty() || brickList.isEmpty()) {
                if (gameState.getNumberOfLifes() == 0) {
                    phaseController.gameOver();
                } else if (brickList.isEmpty()) {
                    gameState.setFinalLevel("");
                    phaseController.finish();
                } else {
                    Ball ball = new Ball(200, 232, 0, 0, 8);
                    scene.addChild(ball);
                    ballList.add(ball);
                    bar.setX(192);
                    phaseController.ballLost();
                    gameStarted = false;
                    timer.stop();
                }
            }
        }
    }
    
    void setTerminar(boolean stop) {
        this.stop = stop;
    }
}
